﻿using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;

using DatabaseGroup.SSIS.SourceAdapters;
using System;

namespace DatabaseGroup.UnitTests.SSIS.SourceAdapters
{
    [TestClass()]
    public class PropertiesManagerTest
    {
        private TestContext _testContextInstance;
        // TODO: think of some better messages that don't state the f-ing obvious
        private const string _expectedPropMessage = "The property value returned was not the same as the one expected";
        private const string _eventMessage = "The event message triggered was not the same as the one expected";

        public TestContext TestContext
        {
            get
            {
                return _testContextInstance;
            }
            set
            {
                _testContextInstance = value;
            }
        }

        [TestMethod()]
        public void ValidateProperties_EmptyPropertyCollection_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager();
            IDTSCustomPropertyCollection100 customPropertyCollection = new CustomPropertyCollectionTestImpl();
            PropertiesManager.AddComponentProperties(customPropertyCollection);

            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID, 
                target.ValidateProperties(customPropertyCollection, DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_DummyStringNameValueWithIsValidOldStatus_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID,
                target.ValidatePropertyValue("AnyName", "AnyValue", DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_DummyStringNameValueWithIsBrokenOldStatus_ReturnIsBrokenStatus()
        {
            PropertiesManager target = new PropertiesManager(); 
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISBROKEN,
                target.ValidatePropertyValue("AnyName", "AnyValue", DTSValidationStatus.VS_ISBROKEN), ExpResult("ISBROKEN"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_IsUnicodePropNameWithTrueValue_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager(); 
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID,
                target.ValidatePropertyValue(PropertiesManager.IsUnicodePropName, true, DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_TreatEmptyStringsAsNullPropNameWithIntValue_ReturnIsCorruptStatus()
        {
            PropertiesManager target = new PropertiesManager();
            target.PostErrorEvent += message => Assert.AreEqual<string>(MessageStrings.InvalidPropertyValue(PropertiesManager.TreatEmptyStringsAsNullPropName, 7), message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISCORRUPT,
                target.ValidatePropertyValue(PropertiesManager.TreatEmptyStringsAsNullPropName, 7, DTSValidationStatus.VS_ISVALID), ExpResult("ISCORRUPT"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_CodePagePropNameWithTrueValue_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager(); 
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID,
                target.ValidatePropertyValue(PropertiesManager.CodePagePropName, true, DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_HeaderRowDelimiterPropNameWithNullValue_ReturnIsCorruptStatus()
        {
            PropertiesManager target = new PropertiesManager();
            target.PostErrorEvent += message => Assert.AreEqual<string>(MessageStrings.InvalidPropertyValue(PropertiesManager.HeaderRowDelimiterPropName, null), message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISCORRUPT,
                target.ValidatePropertyValue(PropertiesManager.HeaderRowDelimiterPropName, null, DTSValidationStatus.VS_ISVALID), ExpResult("ISCORRUPT"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_TextQualifierPropNameWithEmptyValue_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID,
                target.ValidatePropertyValue(PropertiesManager.TextQualifierPropName, string.Empty, DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_ColumnDelimiterPropNameWithLongStringValue_ReturnIsBrokenStatus()
        {
            PropertiesManager target = new PropertiesManager();
            target.PostErrorEvent += message => Assert.AreEqual<string>(MessageStrings.PropertyStringTooLong(
                    PropertiesManager.ColumnDelimiterPropName, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISBROKEN,
                target.ValidatePropertyValue(PropertiesManager.ColumnDelimiterPropName, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", DTSValidationStatus.VS_ISVALID), ExpResult("ISBROKEN"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_RowDelimiterPropNameWithEmptyValue_ReturnIsBrokenStatus()
        {
            PropertiesManager target = new PropertiesManager();
            target.PostErrorEvent += message => Assert.AreEqual<string>(MessageStrings.RowDelimiterEmpty, message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISBROKEN,
                target.ValidatePropertyValue(PropertiesManager.RowDelimiterPropName, string.Empty, DTSValidationStatus.VS_ISVALID), ExpResult("ISBROKEN"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_RowDelimiterPropNameWithEmptyValueAndIsCorruptOldStatus_ReturnIsCorruptStatus()
        {
            PropertiesManager target = new PropertiesManager();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISCORRUPT,
                target.ValidatePropertyValue(PropertiesManager.RowDelimiterPropName, string.Empty, DTSValidationStatus.VS_ISCORRUPT), ExpResult("ISCORRUPT"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_LogSourceDataTypePropNameWithDtStrValue_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID,
                target.ValidatePropertyValue(PropertiesManager.LogSourceDataTypePropName, DataType.DT_STR, DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_LogSourceDataTypePropNameWithDtI4Value_ReturnIsBrokenStatus()
        {
            PropertiesManager target = new PropertiesManager();

            target.PostErrorEvent += message => Assert.AreEqual<string>(
                MessageStrings.InvalidPropertyDataType(PropertiesManager.LogSourceDataTypePropName, DataType.DT_I4.ToString()), message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISBROKEN,
                target.ValidatePropertyValue(PropertiesManager.LogSourceDataTypePropName, DataType.DT_I4, DTSValidationStatus.VS_ISVALID), ExpResult("ISBROKEN"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_LogSourceDataTypePropNameWithNullValue_ReturnIsCorruptStatus()
        {
            PropertiesManager target = new PropertiesManager();

            target.PostErrorEvent += message => Assert.AreEqual<string>(
                MessageStrings.InvalidPropertyValue(PropertiesManager.LogSourceDataTypePropName, null), message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISCORRUPT,
                target.ValidatePropertyValue(PropertiesManager.LogSourceDataTypePropName, null, DTSValidationStatus.VS_ISVALID), ExpResult("ISCORRUPT"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_EscapeCharPropNameWithCharValue_ReturnIsValidStatus()
        {
            PropertiesManager target = new PropertiesManager();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID,
                target.ValidatePropertyValue(PropertiesManager.EscapeCharPropName, '"', DTSValidationStatus.VS_ISVALID), ExpResult("ISVALID"));
        }

        [TestMethod()]
        public void ValidatePropertyValue_EscapeCharPropNameWithNullValue_ReturnIsCorruptStatus()
        {
            PropertiesManager target = new PropertiesManager();

            target.PostErrorEvent += message => Assert.AreEqual<string>(
                MessageStrings.InvalidPropertyValue(PropertiesManager.EscapeCharPropName, null), message, _eventMessage);
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISCORRUPT,
                target.ValidatePropertyValue(PropertiesManager.EscapeCharPropName, null, DTSValidationStatus.VS_ISVALID), ExpResult("ISCORRUPT"));
        }

        [TestMethod()]
        [DeploymentItem("DatabaseGroup.SSIS.SourceAdapters.DelimitedFileSource.dll")]
        public void ValidateDelimiterProperty_ColumnDelimiterPropNameWithCommaValue_ReturnIsValidStatus()
        {
            PropertiesManager_Accessor target = new PropertiesManager_Accessor();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID, target.ValidateDelimiterProperty(PropertiesManager.ColumnDelimiterPropName, ","), ExpResult("ISVALID"));
        }

        [TestMethod()]
        [DeploymentItem("DatabaseGroup.SSIS.SourceAdapters.DelimitedFileSource.dll")]
        public void ValidateDelimiterProperty_RowDelimiterPropNameWithCrLfValue_ReturnIsValidStatus()
        {
            PropertiesManager_Accessor target = new PropertiesManager_Accessor();
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISVALID, target.ValidateRowDelimiterProperty(PropertiesManager.RowDelimiterPropName, "\r\n"), ExpResult("ISVALID"));
        }

        [TestMethod()]
        [DeploymentItem("DatabaseGroup.SSIS.SourceAdapters.DelimitedFileSource.dll")]
        public void ValidateBooleanProperty_IsUnicodePropNameWithStringValue_ReturnIsCorruptStatus()
        {
            PropertiesManager_Accessor target = new PropertiesManager_Accessor(); 
            Assert.AreEqual<DTSValidationStatus>(DTSValidationStatus.VS_ISCORRUPT, target.ValidateBooleanProperty(PropertiesManager.IsUnicodePropName, "blah"), ExpResult("ISCORRUPT"));
        }

        [TestMethod()]
        public void GetPropertyValue_DummyPropertyNameAndValue_ReturnExpectedDummyValue()
        {
            IDTSCustomPropertyCollection100 customPropertyCollection = new CustomPropertyCollectionTestImpl();
            IDTSCustomProperty100 property = customPropertyCollection.New();
            property.Name = "Name";
            property.Value = 77;
            Assert.AreEqual<int>(77, PropertiesManager.GetPropertyValue<int>(customPropertyCollection, "Name"), _expectedPropMessage);
        }

        [TestMethod()]
        [DeploymentItem("DatabaseGroup.SSIS.SourceAdapters.DelimitedFileSource.dll")]
        public void AddCustomProperty_DummyPropertyNameAndValue_CorrectlyAddDummyProperty()
        {
            IDTSCustomPropertyCollection100 customPropertyCollection = new CustomPropertyCollectionTestImpl();
            PropertiesManager_Accessor.AddCustomProperty(customPropertyCollection, "Name", "Description", "Value");

            Assert.AreEqual<string>("Value", PropertiesManager.GetPropertyValue<string>(customPropertyCollection, "Name"), _expectedPropMessage);

            try
            {
                PropertiesManager.GetPropertyValue<object>(customPropertyCollection, "Unexpected");
                Assert.Fail("Expected ArgumentException was not thrown when attempting to access non-existant property");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual<string>("name", ex.ParamName, 
                    "Expected ArgumentException was not thrown with expected message when accessing non-existant property");
            }
            catch
            {
                Assert.Fail("Expected ArgumentException was not thrown when attempting to access non-existant property");
            }
        }

        [TestMethod()]
        [DeploymentItem("DatabaseGroup.SSIS.SourceAdapters.DelimitedFileSource.dll")]
        public void AddCustomProperty_DummyPropertyNameAndValue_CorrectlyAddDummyPropertyWithExpectedValues()
        {
            IDTSCustomPropertyCollection100 customPropertyCollection = new CustomPropertyCollectionTestImpl();
            PropertiesManager_Accessor.AddCustomProperty(customPropertyCollection, "NewName", "Test description", 100.25, "TestConverter");
            IDTSCustomProperty100 prop = customPropertyCollection["NewName"];

            Assert.AreEqual<string>("Test description", prop.Description, _expectedPropMessage);
            Assert.AreEqual<string>("TestConverter", prop.TypeConverter, _expectedPropMessage);
            Assert.AreEqual<double>(100.25, (double)prop.Value, _expectedPropMessage);
        }

        [TestMethod()]
        public void AddComponentProperties_EmptyPropertyCollection_PopulatePropertyCollectionWithDefaultComponentProperties()
        {
            IDTSCustomPropertyCollection100 customPropertyCollection = new CustomPropertyCollectionTestImpl();
            PropertiesManager.AddComponentProperties(customPropertyCollection);

            Assert.AreEqual<string>(",", PropertiesManager.GetPropertyValue<string>(customPropertyCollection, PropertiesManager.ColumnDelimiterPropName), _expectedPropMessage);
            Assert.AreEqual<string>("\r\n", PropertiesManager.GetPropertyValue<string>(customPropertyCollection, PropertiesManager.RowDelimiterPropName), _expectedPropMessage);
            Assert.AreEqual<string>(string.Empty, PropertiesManager.GetPropertyValue<string>(customPropertyCollection, PropertiesManager.TextQualifierPropName), _expectedPropMessage);
            Assert.AreEqual<string>("\r\n", PropertiesManager.GetPropertyValue<string>(customPropertyCollection, PropertiesManager.HeaderRowDelimiterPropName), _expectedPropMessage);
            Assert.AreEqual<bool>(false, PropertiesManager.GetPropertyValue<bool>(customPropertyCollection, PropertiesManager.IsUnicodePropName), _expectedPropMessage);
            Assert.AreEqual<bool>(true, PropertiesManager.GetPropertyValue<bool>(customPropertyCollection, PropertiesManager.TreatEmptyStringsAsNullPropName), _expectedPropMessage);
            Assert.AreEqual<bool>(false, PropertiesManager.GetPropertyValue<bool>(customPropertyCollection, PropertiesManager.ColumnNamesInFirstRowPropName), _expectedPropMessage);
            Assert.AreEqual<int>(1252, PropertiesManager.GetPropertyValue<int>(customPropertyCollection, PropertiesManager.CodePagePropName), _expectedPropMessage);
            Assert.AreEqual<int>(0, PropertiesManager.GetPropertyValue<int>(customPropertyCollection, PropertiesManager.DataRowsToSkipPropName), _expectedPropMessage);
            Assert.AreEqual<int>(0, PropertiesManager.GetPropertyValue<int>(customPropertyCollection, PropertiesManager.HeaderRowsToSkipPropName), _expectedPropMessage);
        }

        /// <summary>
        /// Returns a message detailing the expected result that should have been returned
        /// </summary>
        /// <param name="status">The expected result status</param>
        /// <returns>The error message</returns>
        private string ExpResult(string status)
        {
            string expectedResult = "Expected resulting status to be {0} based on supplied arguments";
            return string.Format(expectedResult, status);
        }
    }
}

